#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include <libxml/parser.h>
#include "email.h"
#include "database.h"
#define ACCOUNT_VERSION       "1.0.0"
#define ACCOUNT_TABLE_ACCOUNT "account"
#define ACCOUNT_FIELD_SOCKET    "socket"
#define ACCOUNT_FIELD_PEER_ID   "peer_id"
#define ACCOUNT_FIELD_ID            "id"
#define ACCOUNT_FIELD_DATA        "data"
enum account_type {
  ACCOUNT_TYPE_PERSON,
  ACCOUNT_TYPE_GROUP,
};
enum read_status {
  READ_STATUS_NO,
  READ_STATUS_YES,
};
enum contact_status {
  CONTACT_STATUS_REQUEST,
  CONTACT_STATUS_BE_REQUESTED,
  CONTACT_STATUS_AGREE,
  CONTACT_STATUS_DISAGREE,
};
int random_int_range(int min, int max)
{
  srand(time(NULL));
  if (min > max) {
    int temp = min;
    min = max;
    max = temp;
  }
  int rand_num = rand();
  return min + rand_num % (max - min + 1);
}
char *err_create (const char *err)
{
  int rc = 0;
  char *res = NULL;
  xmlNodePtr root = NULL, node = NULL;
  xmlBufferPtr xmlbuf = NULL;

  root = xmlNewNode (NULL, BAD_CAST "root");
  node = xmlNewChild (root, NULL, BAD_CAST "child", NULL);
  xmlNewProp (node, BAD_CAST "error", BAD_CAST err);
  xmlbuf = xmlBufferCreate ();
  rc = xmlNodeDump (xmlbuf, NULL, root, 0, 0);
  if (rc == -1) {
    printf("[WARN] xmlnodedump error\n");
    goto out;
  }
  res = strdup ((char *)xmlbuf->content);
out:
  return res;
}
char *account_verification(const char *email, void *db,
    const char *sender, const char *authorizationCode)
{
  void *res = NULL;//, result = NULL;
  char buf[1024] = {0}, verification[32] = {0}, statement[1024] = {0};
  int rc, row_id;

  if (!email) {
    res = err_create ("no email");
    goto out;
  }
  if (strlen(email) < 1) {
    res = err_create ("no email");
    goto out;
  }
  rc = database_exist(db, ACCOUNT_TABLE_ACCOUNT, "email",
      (char *)email);
  if (rc) {
    printf("[DEBUG] The email address exist.\n");
    snprintf(statement, sizeof(statement),
        "select 1 from '%s' where %s='%s' and username not null limit 1;",
        "account", "email", (char *)email);
    rc = database_sql2int(db, statement);
    if (rc) {
      printf("[DEBUG] The email address has been registered.\n");
      res = err_create ("The email address has been registered.");
      goto out;
    } else {
      rc = random_int_range(0, 0xffff);
      snprintf(verification, sizeof(verification), "%d", rc);
      email_send(sender, authorizationCode,
          (char *)email, verification);
      snprintf(buf, sizeof(buf),
          "update %s set verification='%s' where email='%s';",
          ACCOUNT_TABLE_ACCOUNT, verification, email);
      res = database_sql2str(db, buf);
    }
  } else {
    rc = random_int_range(10000, 0xffff);
    snprintf(verification, sizeof verification, "%d", rc);
    email_send(sender, authorizationCode,
        (char *)email, verification);
    snprintf(buf, sizeof(buf),
        "insert into %s (email,verification) values ('%s','%s');",
        ACCOUNT_TABLE_ACCOUNT, (char *)email, verification);
    res = database_sql2str(db, buf);//verification,id
    free (res);
    row_id = database_last_insert_rowid(db);
    //create contact
    snprintf(buf, sizeof(buf),
        "CREATE TABLE 'contacts_%d' ('id'	INTEGER,'limits' INTEGER,	'status'INTEGER);",
        row_id);
    res = database_sql2str(db, buf);//verification,id
    free (res);
    //create history
    snprintf(buf, sizeof(buf),
        "CREATE TABLE 'history_%d' (\"id\"	INTEGER, \"send_id\" INTEGER, \"read_id\" INTEGER, \"msg\"	TEXT, \"time\"	INTEGER, \"type\"	TEXT, \"status\" INTEGER);",
        row_id);
    res = database_sql2str(db, buf);//verification,id
    free (res);
  }
out:
  return res;
}
/*
 * <dev>
 * <dev email="234@qq.com"/>
 * </dev>
 */
char *account_xml_verification(const char *msg, int size, void *db,
    const char *sender, const char *authorizationCode)
{
  //PRINTF_FUNC;
  xmlDocPtr doc = NULL;
  xmlNodePtr root = NULL, child = NULL;
  xmlChar *email = NULL;
  void *res = NULL;//, result = NULL;

  doc = xmlParseMemory(msg, size);
  root = xmlDocGetRootElement (doc);
  child = xmlFirstElementChild (root);
  email = xmlGetProp (child, BAD_CAST "email");
  res = account_verification((char *)email, db,
      sender, authorizationCode);
  xmlFree(doc);
  return res;
}
char *account_sign_up(const char *email, const char *verification,
    const char *usr, const char *pwd, void *sql)
{
  char *res = NULL, *result = NULL;
  char buf[1024] = {0};
  int rc = 0;

  snprintf(buf, sizeof(buf),
      "select 1 from %s where email='%s' and verification='%s';",
      "account", email, verification);
  rc = database_sql2int(sql, buf);
  if (rc) {
    snprintf(buf, sizeof(buf),
        "select 1 from %s where email='%s' and username not null;",
        "account", (char *)email);
    rc = database_sql2int(sql, buf);
    if (rc) {
      res = err_create ("此邮箱已存在");
      goto out;
    }
  } else {
    res = err_create ("验证码错误");
    goto out;
  }
  //g_debug("errno:%d\n", errno);
  //t = g_date_time_to_unix(datetime);
  snprintf(buf, sizeof(buf),
      "update %s set username='%s',pwd='%s' where email='%s' and verification='%s' and username is null;",
      "account", usr, pwd, email, verification);
  res = database_sql2str(sql, buf);
  free (res);
  snprintf(buf, sizeof(buf),
      "select id from %s where email='%s';",
      "account", email);
  res = database_sql2str(sql, buf);
  goto out;
out:
  if (result)
    free (result);
  return res;
}
//<root><child id="8" pwd="3233"/></root>
char *account_xml_sign_up(const char *msg, size_t size, void *db)
{
  xmlDocPtr doc = NULL;
  xmlNodePtr root = NULL, child = NULL;
  xmlChar *email = NULL, *username = NULL, *verification = NULL,
          *pwd = NULL;
  char *res = NULL, *result = NULL;
  //char buf[1024] = {0};
  //int rc = 0;

  doc = xmlParseMemory(msg, size);
  root = xmlDocGetRootElement (doc);
  child = xmlFirstElementChild (root);
  email = xmlGetProp (child, BAD_CAST "email");
  username = xmlGetProp (child, BAD_CAST "username");
  verification = xmlGetProp (child, BAD_CAST "verification");
  pwd = xmlGetProp (child, BAD_CAST "pwd");
  account_sign_up((char *)email, (char *)verification,
      (char *)username, (char *)pwd, db);
  if (email)
    xmlFree (email);
  if (username)
    xmlFree (username);
  if (pwd)
    xmlFree (pwd);
  if (verification)
    xmlFree (verification);
  if (result)
    free (result);
  if (doc)
    xmlFreeDoc(doc);
  return res;
}
char *account_sign_in(const char *usr, const char *pwd, void *sql)
{
  char buf[1024] = {0}, verification[32] = {0};
  char *res = NULL;
  int rc = 0;
  xmlNodePtr root = NULL, child = NULL;
  xmlBufferPtr xmlbuf = NULL;

  snprintf(buf, sizeof(buf),
      "select 1 from %s where id='%s' and pwd='%s';",
      "account", usr, pwd);
  rc = database_sql2int(sql, buf);
  root = xmlNewNode (NULL, BAD_CAST "root");
  child = xmlNewChild (root, NULL, BAD_CAST "child", NULL);
  xmlbuf = xmlBufferCreate ();
  if (rc) {
    rc = random_int_range(0, 0xffff);
    snprintf(verification, sizeof verification, "%d", rc);
    snprintf(buf, sizeof(buf),
        "update %s set verification='%s' where id='%s' and pwd='%s';",
        "account", verification, usr, pwd);
    res = database_sql2str(sql, buf);
    free(res);
    xmlNewProp (child, BAD_CAST "token", BAD_CAST verification);
  } else {
    xmlNewProp (child, BAD_CAST "error", BAD_CAST "id or pwd error");
  }
  rc = xmlNodeDump (xmlbuf, NULL, root, 0, 0);
  if (rc == -1) {
    printf("[WARNING] xmlnodedump error\n");
    goto out;
  }
  if (xmlbuf)
    res = strdup ((char *)xmlbuf->content);
  goto out;
out:
  if (xmlbuf)
    xmlBufferFree (xmlbuf);
  if (root)
    xmlFreeNode (root);
  return res;
}
//<root><child id="8" pwd="3233"/></root>
char *account_xml_sign_in(const char *msg, size_t size, void *sql)
{
  xmlDocPtr doc = NULL;
  xmlNodePtr root = NULL, child = NULL;
  xmlChar *id = NULL, *pwd = NULL;
  char *res = NULL;

  doc = xmlParseMemory(msg, size);
  root = xmlDocGetRootElement (doc);
  child = xmlFirstElementChild (root);
  id = xmlGetProp (child, BAD_CAST "id");
  pwd = xmlGetProp (child, BAD_CAST "pwd");
  account_sign_in((char *)id, (char *)pwd, sql);

  if (doc)
    xmlFreeDoc(doc);
  if (id)
    xmlFree (id);
  if (pwd)
    xmlFree (pwd);
  return res;
}
